<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport"
        content="width=device-width, initial-scale=1.0,minimum-scale=1,maximum-scale=1,user-scalable=no">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <!-- <link rel="stylesheet" type="text/css" href="css/index.css">
    <script type="text/javascript" src="js/index.js"></script>
    <style type="text/css"></style> -->
    <title>Document</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }

        div {
            width: 100px;
            height: 100px;
            background-color: orangered;
            position: absolute;
        }
    </style>
</head>

<body>
    <div class="">
    </div>

    <script>
        /*          明确需求:
        + 当光标按下的时候, 可以拖拽盒子移动
        + 光标松开的时候, 盒子就停留在这个位置

      实现:
        + 问题1: 需要什么事件 ?
          => 事件1: 鼠标按下事件, 按下以后可以在鼠标移动的时候, 让元素跟随移动
          => 事件2: 鼠标抬起事件, 抬起以后, 不让元素跟随鼠标移动了
          => 事件3: 鼠标移动事件, 随着鼠标移动, 实时改变元素的位置
        + 问题2: 三个事件分别绑定给谁 ?
          => 鼠标按下事件
            -> 当我在 div 上按下以后, 表示可以拖拽 div 移动
            -> 事件绑定给 div
          => 鼠标抬起事件
            -> 当我在 div 上抬起以后, 不在继续进行拖拽
            -> 事件绑定给 div
            -> 但是直接绑定给div会出现一个小bug，
            -> 当鼠标在div内按下，鼠标移动到浏览器可视窗口以外的时候鼠标抬起
            -> 鼠标再次进入可视窗口div元素不需要鼠标按下事件就会直接跟着鼠标走
            -> 所以我们直接给document绑定鼠标抬起事件
          => 鼠标移动事件
            -> 为什么不绑定给 div
            -> 因为你移动光标以后, 浏览器需要时间去让 元素改变 位置
            -> 这个时间大概是 16ms
            -> 如果你在 16ms 内快速的移动离开了盒子, 那么就不会在触发事件了
            -> 因为在整个页面里面移动都需要让 div 跟随, 所以事件直接绑定给 document
        + 问题3: mousemove 事件是否需要一直执行 ?
          => 不行, 那么怎么解决 ?
          => 方案1:
            -> 在鼠标按下以后, 在给光标添加移动事件
            -> 在鼠标抬起以后, 在给光标取消移动事件
            -> 方案可行, 但是不好
            -> 因为你每一次按下, 都会给 div 绑定一个事件, 每一次抬起, 都会取消事件
            -> 你在不停地重复的操作给 div 绑定事件, 取消事件的行为
          => 方案2:
            -> 准备一个开关
            -> 之所以会让盒子跟随移动, 是因为 mousemove 的事件处理函数里面的代码在执行
            -> mousemove 事件处理函数里面的代码如果不执行, 那么就不会让盒子跟随移动了
            -> 提前准备一个开关, 在 mousemove 事件里面进行判断
            -> 如果开关是开启状态, 那么继续执行后续代码
            -> 如果开关是关闭状态, 那么直接结束函数, 不在继续执行了
            -> 在鼠标按下的时候, 打开开关
            -> 在鼠标抬起的时候, 关闭开关
        + 问题4: 如何让元素跟随移动 ?
          => 在 mousemove 事件里面, 获取到光标的坐标点
          => 实时赋值给 div 的 left 和 top
        + 问题5: 光标一直在左上角, 能不能让光标放在中间 ?
          => 只要在拿到的坐标点上减去盒子宽高的一半
        + 问题6: 不想要光标一直在元素中央，想要让元素在哪里按下，元素就在哪里跟着走？
          => 只需要在鼠标按下操作的时候获取光标相对于元素左上角的距离
          => 然后在计算时用光标的在文档中的位置减去光标相对于元素左上角的位置就能得到光标实际按下时的元素跟随的位置*/


        let div = document.querySelector('div')
        //console.log(div);
        let flag = false //定义一个开关判断鼠标的状态
        let _offsetX, _offsetY
        div.onmousedown = function (e) {
            flag = true
            //console.log('鼠标按下');
            //鼠标按下时，鼠标相对于元素左上角地距离，以下两种方法都能实现，随便选一种
            /* _offsetX=e.pageX-div.offsetLeft
            _offsetY=e.pageY-div.offsetTop */
            _offsetX = e.offsetX
            _offsetY = e.offsetY
        }
        document.onmouseup = function (e) {
            flag = false
            //console.log('鼠标抬起');
        }
        document.onmousemove = function (e) {
            if (flag === false)
                return
            //console.log('鼠标移动');
            //此方法鼠标移动时光标始终在元素正中央
            /* let x=e.pageX-div.offsetWidth/2
            let y=e.pageY-div.offsetHeight/2 */
            //此方法鼠标移动时光标始终在按下位置
            let x = e.pageX - _offsetX
            let y = e.pageY - _offsetY
            /* 以下两种方法都能实现边界值的判定，随便选一种 */
            /* if(x<=0)x=0
            if(y<=0)y=0
            if(x>document.documentElement.clientWidth-div.offsetWidth)
                x=document.documentElement.clientWidth-div.offsetWidth
            if(y>document.documentElement.clientHeight-div.offsetHeight)
                y=document.documentElement.clientHeight-div.offsetHeight */
            x = Math.min(Math.max(0, x), document.documentElement.clientWidth - div.offsetWidth)
            y = Math.min(Math.max(0, y), document.documentElement.clientHeight - div.offsetHeight)
            div.style.left = x + 'px'
            div.style.top = y + 'px'
        }
    </script>
</body>

</html>